/*
 * @Description: [封装Uniapp请求]
 * @Author: Iseven Monkey <iswoter@gmail.com>
 * @Date: 2023-10-20 10:37:34
 * @LastEditors: Iseven Monkey <iswoter@gmail.com>
 * @LastEditTime: 2023-11-19 20:57:05
 */

// 引入vuex
import store from "@/store";

// 引入全局配置
import globalConfig from "@/config";

/**
 * @description: 接口返回数据格式示例
 * * {
 * *   "statusCode": 200, // 状态码 200 为成功, 401 为未登录, 403 为无权限, 404 为接口不存在, 405 为未认证, 406 为未授权, 500 为服务器错误
 * *   "message": "", // 提示信息
 * *   "data": {}, // 返回数据
 * *   "token": null,  // token
 * *   "user": null, // 用户信息
 * * }
 */

export default (options) => {
  // * 暴露一个 function：myRequest，使用options接收页面传过来的参数
  return new Promise((resolve, reject) => {
    console.log("options", options);
    // 如果需要展示loading
    if (!("loading" in options)) {
      options.loading = true;
    }

    // 显示loading
    if (options.loading) {
      uni.showLoading();
    }

    // 请求方式
    const method = String(options.method || "GET").toUpperCase();

    // 请求头
    let header = {
      Authorization: store.state.auth.token || "", // token
    };

    // 如果不是上传文件
    if (method != "UPLOAD") {
      header["content-type"] = "application/json";
    }

    // ! 将options中的header属性添加到header中,优先级：options > header
    header = {
      ...header,
      ...options.header,
    };

    // 请求参数
    let params = {
      url: globalConfig.apiUrl + options.url, //接收请求的API
      method,
      header,
      data: options.data || {}, //接收请求的data,不传默认为空
      success: (res) => {
        // 如果是上传文件，返回的数据是字符串，需要转换成对象
        const data = method === "UPLOAD" && res.data ? JSON.parse(res.data) : res.data || {};

        // 授权操作
        const authAction = () => {
          // 清除用户信息
          store.dispatch("auth/clear");

          // 如果需要登录
          if (options.auth) {
            // 执行授权操作
            store.dispatch("auth/auth", { resData: true }).then((res) => {
              if (res.status === 200) {
                uni.showToast({
                  icon: "none",
                  title: "已进行登录，请重新操作！",
                });
              }

              reject(data);
            });
          }
        };

        // 如果有token，就存储token
        if (data.token) {
          store.commit("auth/setToken", data.token);
        }

        // 如果有用户信息
        if (data.user) {
          store.commit("auth/setUser", data.user);
        }

        // 如果有用户扩展信息
        if (data.userExtend) {
          const userExtend = data.userExtend.data || {};
          store.commit("auth/setUserExtend", userExtend);
        }

        // 如果有设置信息 并且不为空 数组或者空对象
        if (
          data.settings &&
          ((Array.isArray(data.settings) && data.settings.length > 0) ||
            Object.keys(data.settings).length > 0)
        ) {
          store.dispatch("settings/setSettings", data.settings);
        }

        // 如果token无效
        if (data.tokenInvalid || data.clearToken) {
          authAction();
        }

        // 如果状态码不是200
        if (res.statusCode !== 200) {
          // 如果是404
          if (res.statusCode === 404) {
            uni.showToast({
              icon: "none",
              title: "请求地址不存在！",
            });
            return reject(data);
          }

          // 因为200是返回成功的状态码，如果不等于200,则代表获取失败
          // 正则表达式判断 data.status 包含  401 403 405 406

          const reg = /40[1-9]/g;
          if (reg.test(res.statusCode)) {
            // authAction();

            return reject(data);
          }

          uni.showToast({
            icon: "none",
            title: data.msg || "数据获取失败！",
          });

          return reject(data);
        }

        // 成功,将数据返回
        resolve(data);
      },
      complete: () => {
        // 隐藏loading
        options.loading && uni.hideLoading();
      },
      fail: (err) => {
        console.log("err", err);
        return uni.showToast({
          icon: "none",
          title: err.errMsg.includes("request:fail") ? "请求失败" : err.errMsg || "数据获取失败！",
        });
      },
    };

    // 删除options中的url属性
    delete options.url;
    // 删除options中的method属性
    delete options.method;
    // 删除options中的data属性
    delete options.data;
    // 删除options中的header属性
    delete options.header;

    // ! 将options中的属性添加到params中,优先级：options > params
    params = {
      ...params,
      ...options,
    };

    // 如果是上传文件
    if (method === "UPLOAD") {
      // 删除params中的method属性
      delete params.method;
      // ! 上传文件
      uni.uploadFile(params);
    } else {
      // ! 发送请求

      uni.request(params);
    }
  });
};
